import mx.utils.Delegate;

import gugga.sequence.TaskManager;
import gugga.sequence.FictiveTask;
import gugga.sequence.ExecuteAsyncMethodTask;
import gugga.common.EventDescriptor;

import guggaLibTests.support.TaskExecutionEvaluator;
import guggaLibTests.support.PauseResumeMethodsSequence;

import test_framework.test.unit.TestCase;
import gugga.common.ITask;
import gugga.sequence.PreconditionsTask;
import gugga.sequence.PreconditionsManager;
import gugga.utils.DebugUtils;
import mx.events.EventDispatcher;
import gugga.debug.Debugger;
import gugga.components.XMLLoader;

/**
 * @author vladimir
 */
class guggaLibTests.TaskManagerTest 
		extends TestCase
{
	private var delayInterval:Number;
	
	public function TaskManagerTest()
	{
		super();
		
		this.delayInterval = 1000;
	}
	
	public function testConstructor()
	{
		var taskManager:TaskManager = new TaskManager();
		assertNotNull(
				"taskManager should not be null after creation", 
				taskManager);
		assertNotUndefined(
				"taskManager should not be undefined after creation", 
				taskManager);
		
		var tasks:Array = taskManager.Tasks;
		assertEquals(
				"tasks should be empty(taskManager still has no TaskManagerItem items)", 
				tasks.length, 
				0);
	}
	
	public function testAddStartingTasks()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var taskManager:TaskManager = new TaskManager();
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveTask:FictiveTask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var eventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				eventSource, 
				"start");
		
		/** 
		 * the execution of the following lines will throw exception(the logic 
		 * for addStartingTasks has been changed):
		 * <code>
		 * 	taskManager.addTaskWithPreconditions(fictiveTask, [precondition]);
		 * 	taskManager.addStartingTasks([fictiveTask]);
		 * </code>
		 * but this will work:
		 */
		taskManager.addStartingTasks([fictiveTask]);
		taskManager.addTaskPreconditions(fictiveTask, [precondition]);
		
		/**
		 * <code>addStartingTasks(aTasks : Array)</code> will create and add 
		 * new <code>TaskManagerItem</code> item to the 
		 * <code>TaskManager</code> and exception will be raised if any of the 
		 * specified tasks is already associated with existing 
		 * <code>TaskManagerItem</code>. It will also add a precondition to 
		 * wait for <b><i>start</i></b> event from the <code>TaskManager</code> 
		 * task, in order to start the <code>TaskManagerItem</code> item's 
		 * execution. The associated <code>TaskManagerItem</code> items will 
		 * start only if the <code>TaskManager</code> task is started, and 
		 * never before it.
		 * 
		 * How to assert this behaviour?
		 * <code>
		 * 	assertThrows(
		 * 			"this task is already added with addStartingTasks", 
		 * 			taskManager.addStartingTasks([fictiveTask]));
		 * </code>
		 */
		
		taskManager.start();
		
		// taskManager is started, but fictiveTask should not be started yet:
		evaluator.registerRequiredTaskStatus({task:taskManager, event:"start"});
		evaluator.evaluateTaskExecution();
		
		// in order to start fictiveTask the specified precondition should be 
		// met:
		eventSource.start();
		
		// now fictiveTask should be started:
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		evaluator.evaluateTaskExecution();
	}
	
	public function testSetStartingTask()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var taskManager:TaskManager = new TaskManager();
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
				
		var fictiveTask:FictiveTask = new FictiveTask();
		
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var eventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				eventSource, 
				"start");
		
		taskManager.addTaskWithPreconditions(fictiveTask, [precondition]);
		taskManager.setStartingTask(fictiveTask);
		
		taskManager.start();
		
		// taskManager is started, but fictiveTask should not be started yet:
		evaluator.registerRequiredTaskStatus({task:taskManager, event:"start"});
		evaluator.evaluateTaskExecution();
		evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("only taskManager should be started at this point");
		
		// in order to start fictiveTask the specified precondition should be 
		// met:
		eventSource.start();
		
		// now fictiveTask should be started:
		evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
		evaluator.evaluateTaskExecution();
	}
	
	public function testStartWithoutFinalPreconditions()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var taskManager:TaskManager = new TaskManager();
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveTask1:FictiveTask = new FictiveTask();
		var fictiveTask2:FictiveTask = new FictiveTask();
		
		fictiveTask1.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		fictiveTask2.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		taskManager.addTaskWithPreconditions(fictiveTask1, []);
		taskManager.addTaskWithPreconditions(fictiveTask2, []);
		
		taskManager.start();
		
		// after starting the taskManager, the fictiveTask1 and fictiveTask2 
		// should also be started:
		evaluator.registerRequiredTaskStatus({task:taskManager, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask1, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask2, event:"start"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testStartWithFinalPreconditions()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var taskManager:TaskManager = new TaskManager();
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		taskManager.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		var fictiveTask1:FictiveTask = new FictiveTask();
		fictiveTask1.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		fictiveTask1.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
			
		var fictiveTask2:FictiveTask = new FictiveTask();
		fictiveTask2.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		fictiveTask2.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		taskManager.addTaskWithPreconditions(fictiveTask1, []);
		taskManager.addTaskWithPreconditions(fictiveTask2, []);
		
		var finalPrecondition1:EventDescriptor = new EventDescriptor(
				fictiveTask1, 
				"completed");
		var finalPrecondition2:EventDescriptor = new EventDescriptor(
				fictiveTask2,
				"completed");
		
		taskManager.addFinalPreconditions(
				[finalPrecondition1, finalPrecondition2]);
		
		taskManager.start();
		
		// after starting the taskManager, the fictiveTask1 and fictiveTask2 
		// should also be started, and completed right after the start:
		evaluator.registerRequiredTaskStatus({task:taskManager, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask1, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask2, event:"start"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask1, event:"completed"});
		evaluator.registerRequiredTaskStatus({task:fictiveTask2, event:"completed"});
		// after completion of fictiveTask1 and fictiveTask2, taskManager meets 
		// all of its final preconditions and should be completed too:
		evaluator.registerRequiredTaskStatus({task:taskManager, event:"completed"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testInterruptBeforeStart()
	{
		// initialize TaskExecutionEvaluator:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var taskManager:TaskManager = new TaskManager();
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		taskManager.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		var fictiveTask:FictiveTask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		fictiveTask.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		taskManager.addTaskWithPreconditions(fictiveTask, []);
		
		evaluator.assertTaskStatusRegisterIsEmpty("taskManager has not started yet, so no event were caught and consumed");
		
		taskManager.interrupt();
		
		evaluator.registerRequiredTaskStatus({task:taskManager, event:"interrupted"});
		
		// fictiveTask won't be interrupted, because its taskManagerItem is not 
		// in a running state, before start()!!!
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testInterruptAfterCompleted()
	{
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var taskManager:TaskManager = new TaskManager();
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		taskManager.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		taskManager.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		var fictiveTask:FictiveTask = new FictiveTask();
		fictiveTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		fictiveTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		fictiveTask.addEventListener(
				"interrupted", 
				Delegate.create(evaluator, evaluator.onTaskInterrupted));
		
		taskManager.addTaskWithPreconditions(fictiveTask, []);
		
		var startAndCompleteTaskManager:Function = function()
		{
			taskManager.start();
		
			// after starting the taskManager, the fictiveTask should also be 
			// started, and completed right after the start:
			evaluator.registerRequiredTaskStatus({task:taskManager, event:"start"});
			evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"start"});
			evaluator.registerRequiredTaskStatus({task:fictiveTask, event:"completed"});
			// after completion of fictiveTask, taskManager meets all of its final 
			// preconditions and should be completed too:
			evaluator.registerRequiredTaskStatus({task:taskManager, event:"completed"});
		};
		
		var assertCompletedAndInterrupt:Function = function()
		{
			evaluator.evaluateTaskExecution();
			
			taskManager.interrupt();
		
			evaluator.registerRequiredTaskStatus({task:taskManager, event:"interrupted"});
			// fictiveTask won't be interrupted, because its taskManagerItem is not 
			// in a running state, after its completion!!!
		};
		
		var assertOnlyTaskManagerInterrupted:Function = function()
		{
			evaluator.evaluateTaskExecution();
			
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister(
					"Only taskManager should be interrupted");
		};
		
		var testSequence:PauseResumeMethodsSequence 
			= new PauseResumeMethodsSequence(
					this, 
					this.delayInterval, 
					[startAndCompleteTaskManager, 
					assertCompletedAndInterrupt, 
					assertOnlyTaskManagerInterrupted]);
		
		testSequence.start();
	}
	
	/**
	 * This test should assure that if we start the <code>TaskManager</code> 
	 * and add a task with precondition which is still not met, the newly added 
	 * task should not get started.
	 */
	public function testAddTaskWithUnmetPreconditionWhenTaskManagerStarted()
	{
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var taskManager:TaskManager = new TaskManager(true);
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		
		var fictiveTask1:FictiveTask = new FictiveTask();
		var eventDescriptor1:EventDescriptor = new EventDescriptor(
				fictiveTask1, 
				"completed");
		var asyncTask1:ExecuteAsyncMethodTask = ExecuteAsyncMethodTask.create(
				eventDescriptor1, 
				this, 
				this.emptyMethod, 
				[]);
		asyncTask1.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		asyncTask1.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		var fictiveTask2:FictiveTask = new FictiveTask();
		var eventDescriptor2:EventDescriptor = new EventDescriptor(
				fictiveTask2, 
				"completed");
		var asyncTask2:ExecuteAsyncMethodTask = ExecuteAsyncMethodTask.create(
				eventDescriptor2, 
				this, 
				this.emptyMethod, 
				[]);
		asyncTask2.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		asyncTask2.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		var fictiveTask3:FictiveTask = new FictiveTask();
		var fictivePrecondition:EventDescriptor = new EventDescriptor(
				fictiveTask3, 
				"completed");
		
		var startTaskManager:Function = function()
		{
			taskManager.setFinalTask(asyncTask2);
			taskManager.addStartingTask(asyncTask1);
			taskManager.start();
			
			evaluator.registerRequiredTaskStatus({task:taskManager, event:"start"});
			evaluator.registerRequiredTaskStatus({task:asyncTask1, event:"start"});
		};
		
		var assertStartedAndAddNewTaskWithUnmetPrecondition:Function = function()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister(
					"There should be no registered completed events");
			
			this.assertTrue(
					"taskManager should be running now, before adding asyncTask2 with precondition", 
					taskManager.isRunning());
			taskManager.addTaskWithPrecondition(asyncTask2, fictivePrecondition);
		};
		
		var assertNewlyAddedTaskIsNotStarted:Function = function()
		{
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister(
					"There should be no more started or completed events");
		};
		
		var completeAsyncTask1:Function = function()
		{
			// complete asyncTask1:
			fictiveTask1.start();
			
			evaluator.registerRequiredTaskStatus({task:asyncTask1, event:"completed"});
		};
		
		var assertAsyncTask1CompletedAndTaskManagerInNotCompleted:Function = function()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister(
				"TaskManager should not be completed yet");
		};
		
		var meetAsyncTask2Precondition:Function = function()
		{
			// meet precondition in order to start asyncTask2:
			fictiveTask3.start();
			evaluator.registerRequiredTaskStatus({task:asyncTask2, event:"start"});
		};
		
		var assertAsyncTask2Started:Function = function()
		{
			evaluator.evaluateTaskExecution();
		};
		
		var testSequence:PauseResumeMethodsSequence 
			= new PauseResumeMethodsSequence(
					this, 
					this.delayInterval, 
					[startTaskManager, 
					assertStartedAndAddNewTaskWithUnmetPrecondition, 
					assertNewlyAddedTaskIsNotStarted,
					completeAsyncTask1, 
					assertAsyncTask1CompletedAndTaskManagerInNotCompleted, 
					meetAsyncTask2Precondition, 
					assertAsyncTask2Started]);
		
		testSequence.start();
	}
	
	public function testIsRunning()
	{
		var taskManager : TaskManager = new TaskManager();
		
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		
		var completionTask : ITask = new FictiveTask();
		var completionDescriptor : EventDescriptor = new EventDescriptor(
			completionTask,
			"completed"
		);
		
		taskManager.addStartingTask(task1);
		taskManager.addTaskWithPredecessor(task2, task1);
		taskManager.setFinalTask(task2);
		
		taskManager.addFinalPreconditions([completionDescriptor]);
		
		assertFalse(
			"the task manager has not started yet, so the isRunning() should be false",
			taskManager.isRunning()
		);
		
		taskManager.start();
		
		assertTrue(
			"the task manager has already started, so the isRunning() should be true",
			taskManager.isRunning()
		);
		
		completionTask.start();
		
		assertFalse(
			"the task manager has completed, so the isRunning() should be false",
			taskManager.isRunning()
		);
	}
	
	public function testIsImmediatelyInterruptable ()
	{
		var taskManager : TaskManager = new TaskManager();
		
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		
		var completionTask : ITask = new FictiveTask();
		var completionDescriptor : EventDescriptor = new EventDescriptor(
			completionTask,
			"completed"
		);
		
		var completionTaskAsyncTask : ITask = new FictiveTask();
		var completionDescriptorAsyncTask : EventDescriptor = new EventDescriptor(
			completionTaskAsyncTask,
			"completed"
		);
		
		taskManager.addStartingTask(task1);
		taskManager.addTaskWithPredecessor(task2, task1);
		taskManager.setFinalTask(task2);
		
		taskManager.addFinalPreconditions([completionDescriptor]);
		
		/* its not running and isImmediatelyInterruptable says it is not interruptable 
		 * 
		 * it should say it is immediately interruptable -
		 * whenever you ask the task manager if it is immediately interruptable
		 * it doesn't matter if the interruption is not necessary, 
		 * but it matters that immediately after the interruption call 
		 * the task manager won't be running
		 */
		assertTrue(
			"the task manager has not started yet, so isImmediatelyInterruptable should be true",
			taskManager.isImmediatelyInterruptable()
		);
		
		taskManager.start();
		
		// it is running and:

		// it is immediately interruptable but isImmediatelyInterruptable says its not
		assertTrue(
			"the task manager is running and is immediately interruptable, but isImmediatelyInterruptable is false",
			taskManager.isImmediatelyInterruptable()
		);
	}
	
	public function testIsImmediatelyInterruptableWhenItsNot ()
	{
		var taskManager : TaskManager = new TaskManager();
		
		var completionInvoker : ITask = new FictiveTask();
		var completionInvokerDescription : EventDescriptor = new EventDescriptor(
			completionInvoker,
			"completed"
		);

		// XMLLoader is not immediately interruptable task:
		var task1 : ITask = new XMLLoader();
		
		taskManager.addStartingTask(task1);
		taskManager.setFinalTask(task1);
		
		taskManager.start();
		
		assertFalse(
			"the task manager is running and is not immediately interruptable, but isImmediatelyInterruptable is true",
			taskManager.isImmediatelyInterruptable()
		);
	}
	
	public function testIsImmediatelyInterruptableWhenItsNotAndNewTasksIsAppendedWhileRunning ()
	{
		var taskManager : TaskManager = new TaskManager();
		
		var completionInvoker : ITask = new FictiveTask();
		var completionInvokerDescription : EventDescriptor = new EventDescriptor(
			completionInvoker,
			"completed"
		);
		var task1 : ITask = ExecuteAsyncMethodTask.create(
			completionInvokerDescription,
			this,
			this.emptyMethod,
			null
		);
		
		var completionInvoker2 : ITask = new FictiveTask();
		var completionInvokerDescription2 : EventDescriptor = new EventDescriptor(
			completionInvoker2,
			"completed"
		);
		
		// XMLLoader is not immediately interruptable task:
		var task2 : ITask = new XMLLoader();
		
		taskManager.addStartingTask(task1);
		
		taskManager.start();
		this.assertTrue(
				"taskManager should be running now, before adding task2", 
				taskManager.isRunning());
				
		taskManager.addTaskWithPrecondition(task2, completionInvokerDescription2);
		completionInvoker2.start();
		
		assertFalse(
			"the task manager is running and is not immediately interruptable, but isImmediatelyInterruptable is true",
			taskManager.isImmediatelyInterruptable()
		);
	}

	public function testAcceptPrecondition ()
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var manager : TaskManager = new TaskManager(false);
		var task1 : ITask = new FictiveTask();
		var finalilzationTask : ITask = new FictiveTask();
		
		var managerStartDescriptor : EventDescriptor = new EventDescriptor(
			manager,
			"start"
		); 
		var finalizationDescriptor : EventDescriptor = new EventDescriptor(
			finalilzationTask,
			"completed"
		);
		
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		manager.addStartingTask(task1);
		manager.addFinalPreconditions([finalizationDescriptor]);
		
		manager.acceptPrecondition(managerStartDescriptor);
		manager.acceptPrecondition(finalizationDescriptor);

		evaluator.registerRequiredTaskStatus( {task:manager , event: "completed"} );
		
		manager.start();
		
		finalilzationTask.start();
		
		evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("
			the task manager is not completed, but it should be
		");		
	}
	
	public function testAcceptEventSource ()
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var manager : TaskManager = new TaskManager(false);
		var task1 : ITask = new FictiveTask();
		var finalilzationTask : ITask = new FictiveTask();
		
		var finalizationDescriptor : EventDescriptor = new EventDescriptor(
			finalilzationTask,
			"completed"
		);
		
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		manager.addStartingTask(task1);
		manager.addFinalPreconditions([finalizationDescriptor]);
		
		manager.acceptEventSource(manager);
		manager.acceptEventSource(finalilzationTask);

		evaluator.registerRequiredTaskStatus( {task:manager , event: "completed"} );
		
		manager.start();
		
		finalilzationTask.start();
		
		evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("
			the task manager is not completed, but it should be
		");		
	}
	
	public function testAcceptAll ()
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var manager : TaskManager = new TaskManager(false);
		var task1 : ITask = new FictiveTask();
		var finalilzationTask : ITask = new FictiveTask();
		
		var finalizationDescriptor : EventDescriptor = new EventDescriptor(
			finalilzationTask,
			"completed"
		);
		
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		manager.addStartingTask(task1);
		manager.addFinalPreconditions([finalizationDescriptor]);
		
		manager.acceptAll();
		
		evaluator.registerRequiredTaskStatus( {task:manager , event: "completed"} );
		
		manager.start();
		
		finalilzationTask.start();
		
		evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("
			the task manager is not completed, but it should be
		");		
	}

	public function testIgnorePreconditionForFinalPreconditions () 
	{
		var manager : TaskManager = new TaskManager(true);
		var task1 : ITask = new FictiveTask();
		var finalilzationTask : ITask = new FictiveTask();
		
		var finalizationDescriptor : EventDescriptor = new EventDescriptor(
			finalilzationTask,
			"completed"
		);
		
		manager.addStartingTask(task1);
		manager.addFinalPreconditions([finalizationDescriptor]);
		
		manager.start();
		
		manager.ignorePrecondition(finalizationDescriptor);
		
		finalilzationTask.start();
		
		assertTrue(
			"manager is not running, but it should be",
			manager.isRunning()
		);
	}

	public function testIgnoreEventSourceForFinalPreconditions ()
	{
		var manager : TaskManager = new TaskManager(true);
		var task1 : ITask = new FictiveTask();
		var finalilzationTask : ITask = new FictiveTask();
		 
		var finalizationDescriptor : EventDescriptor = new EventDescriptor(
			finalilzationTask,
			"completed"
		);
		
		manager.addStartingTask(task1);
		manager.addFinalPreconditions([finalizationDescriptor]);
		
		manager.start();
		
		manager.ignoreEventSource(finalilzationTask);
		
		finalilzationTask.start();
		
		assertTrue(
			"manager is not running, but it should be",
			manager.isRunning()
		);	
	}
	
	public function testIgnoreAllForFinalPreconditions () 
	{
		var manager : TaskManager = new TaskManager(true);
		var task1 : ITask = new FictiveTask();
		var finalilzationTask : ITask = new FictiveTask();

		var finalizationDescriptor : EventDescriptor = new EventDescriptor(
			finalilzationTask,
			"completed"
		);
		
		manager.addStartingTask(task1);
		manager.addFinalPreconditions([finalizationDescriptor]);
		
		manager.start();
		
		manager.ignoreAll();
		
		finalilzationTask.start();
		
		assertTrue(
			"manager is not running, but it should be",
			manager.isRunning()
		);
	}

	public function testIgnorePreconditionForTask () 
	{
		var manager : TaskManager = new TaskManager(true);
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var task2PreconditionTask : ITask = new FictiveTask(); 
		
		var task2Precondition : EventDescriptor = new EventDescriptor(
			task2PreconditionTask,
			"completed"
		);
		
		manager.addStartingTask(task1);
		manager.addTaskWithPrecondition(task2, task2Precondition);
		manager.addFinalPreconditions([task2Precondition]);
		manager.ignorePrecondition(task2Precondition);
		
		manager.start();
		
		task2PreconditionTask.start();
		
		assertTrue(
			"manager is not running, but it should be",
			manager.isRunning()
		);
	}

	public function testIgnoreEventSourceForTask () 
	{
		var manager : TaskManager = new TaskManager(true);
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var task2PreconditionTask : ITask = new FictiveTask(); 
		
		var task2Precondition : EventDescriptor = new EventDescriptor(
			task2PreconditionTask,
			"completed"
		); 
		
		manager.addStartingTask(task1);
		manager.addTaskWithPrecondition(task2, task2Precondition);
		manager.addFinalPreconditions([task2Precondition]);
		manager.ignoreEventSource(task2PreconditionTask);
		
		manager.start();
		
		task2PreconditionTask.start();
		
		assertTrue(
			"manager is not running, but it should be",
			manager.isRunning()
		);
	}
	
	public function testIgnoreAllForTask () 
	{
		var manager : TaskManager = new TaskManager(true);
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var task2PreconditionTask : ITask = new FictiveTask(); 
		
		var task2Precondition : EventDescriptor = new EventDescriptor(
			task2PreconditionTask,
			"completed"
		); 
		
		manager.addStartingTask(task1);
		manager.addTaskWithPrecondition(task2, task2Precondition);
		manager.addFinalPreconditions([task2Precondition]);
		manager.ignoreAll();
		
		manager.start();
		
		task2PreconditionTask.start();
		
		assertTrue(
			"manager is not running, but it should be",
			manager.isRunning()
		);
	}

	public function testAddTaskWithPrecondition ()
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var preconditionTask : ITask = new FictiveTask();
		var precondition : EventDescriptor = new EventDescriptor(
			preconditionTask,			
			"completed"
		);
		
		var manager : TaskManager = new TaskManager(true);
		
		manager.addStartingTask(task1);
		manager.addTaskWithPrecondition(task2, precondition);
		manager.setFinalTask(task2);
		
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task2.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task2.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		
		var firstBlock = function ()
		{
			evaluator.registerRequiredTaskStatus({task:manager, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"completed"});
			
			manager.start();	
		};
		
		var secondBlock = function () 
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister();
		
			evaluator.registerRequiredTaskStatus({task:task2,event:"start"});
			evaluator.registerRequiredTaskStatus({task:task2,event:"completed"});
			evaluator.registerRequiredTaskStatus({task:manager,event:"completed"});
			
			preconditionTask.start();		
		};
		
		var thirdBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister();
		};
		
		var pauseAndResumer = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock,
			thirdBlock]
		);
		
		pauseAndResumer.start();
	}
	
	public function testAddTaskPrecondition ()
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var preconditionTask : ITask = new FictiveTask();
		var precondition : EventDescriptor = new EventDescriptor(
			preconditionTask,			
			"completed"
		);
		
		var manager : TaskManager = new TaskManager(true);
		
		manager.addStartingTask(task1);
		manager.addStartingTask(task2);
		manager.addTaskPrecondition(task2, precondition);
		manager.setFinalTask(task2);
		
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task2.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task2.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		
		evaluator.registerRequiredTaskStatus({task:manager, event:"start"});
		evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
		evaluator.registerRequiredTaskStatus({task:task1, event:"completed"});

		manager.start();
		
		evaluator.evaluateTaskExecution();
		evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered tasks doesnt match the required ones");
		
		evaluator.registerRequiredTaskStatus({task:task2,event:"start"});
		evaluator.registerRequiredTaskStatus({task:task2,event:"completed"});
		evaluator.registerRequiredTaskStatus({task:manager,event:"completed"});
		
		preconditionTask.start();
		
		evaluator.evaluateTaskExecution();
	}
	
	public function testRemoveTaskPrecondition ()
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var task3 : ITask = new FictiveTask();
		var preconditionTask : ITask = new FictiveTask();
		var precondition : EventDescriptor = new EventDescriptor(
			preconditionTask,			
			"completed"
		);
		var preconditionTask2 : ITask = new FictiveTask();
		var precondition2 : EventDescriptor = new EventDescriptor(
			preconditionTask2,			
			"completed"
		);
		
		var manager : TaskManager = new TaskManager(true);
		
		manager.addStartingTask(task1);
		manager.addStartingTask(task2);
		manager.addTaskPrecondition(task2, precondition);
		manager.addTaskWithPrecondition(task3, precondition2);
		manager.setFinalTask(task3);
		
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task2.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task2.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task3.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task3.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		
		var firstBlock = function () 
		{
			evaluator.registerRequiredTaskStatus({task:manager, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"completed"});
		
			manager.start();
		};
		
		var secondBlock = function ()
		{
			manager.removeTaskPrecondition(task3, precondition2);
			
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
			
			evaluator.registerRequiredTaskStatus({task:task2,event:"start"});
			evaluator.registerRequiredTaskStatus({task:task2,event:"completed"});
			evaluator.registerRequiredTaskStatus({task:task3,event:"start"});
			evaluator.registerRequiredTaskStatus({task:task3,event:"completed"});
			evaluator.registerRequiredTaskStatus({task:manager,event:"completed"});
			
			preconditionTask.start();
		};
		
		var thirdBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock,
			thirdBlock]
		);
		pauseAndResumer.start();
	}
	
	public function testAddFinalPreconditions () 
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var manager :  TaskManager = new TaskManager();
		var task1 : ITask = new FictiveTask();
		var preconditionTask = new FictiveTask();
		var precondition : EventDescriptor = new EventDescriptor(
			preconditionTask,
			"completed"
		);
		
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		manager.addStartingTask(task1);
		manager.addFinalPreconditions([precondition]);
		manager.setFinalTask(task1);
		
		evaluator.registerRequiredTaskStatus({task:manager, event:"start"});
		evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
		evaluator.registerRequiredTaskStatus({task:task1, event:"completed"});
		
		var firstBlock = function ()
		{
			manager.start();
		};
		
		var secondBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
			
			evaluator.registerRequiredTaskStatus({task:manager, event:"completed"});
			
			preconditionTask.start();
		};
		
		var thirdBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock,
			thirdBlock]
		);
		pauseAndResumer.start();
	}
	
	public function testAddFinalPreconditionsAfterStart () 
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var manager :  TaskManager = new TaskManager(true);
		var task1 : ITask = new FictiveTask();
		var preconditionTask = new FictiveTask();
		var finalPreconditionTask = new FictiveTask();
		var finalPrecondition : EventDescriptor = new EventDescriptor(
			finalPreconditionTask,
			"completed"
		);
		var precondition : EventDescriptor = new EventDescriptor(
			preconditionTask,
			"completed"
		);
		
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		manager.addStartingTask(task1);
		manager.setFinalTask(task1);
		manager.addTaskPrecondition(task1, precondition);
		manager.addFinalPreconditions([finalPrecondition]);
		
		
		
		var firstBlock = function ()
		{
			evaluator.registerRequiredTaskStatus({task:manager, event:"start"});
			manager.start();
		};
		
		var secondBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
			
			evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"completed"});
			
			preconditionTask.start();
		};
		
		var thirdBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
			
			finalPreconditionTask.start();
			
			evaluator.registerRequiredTaskStatus({task:manager, event:"completed"});
		};
		
		var fourthBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock,
			thirdBlock,
			fourthBlock]
		);
		pauseAndResumer.start();
	}
	
	public function testRemoveFinalPrecondition () 
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var task1 : ITask = new FictiveTask();
		
		var finalPreconditionTask : ITask = new FictiveTask();
		var finalPrecondition : EventDescriptor = new EventDescriptor(
			finalPreconditionTask,			
			"completed"
		);
		
		var manager : TaskManager = new TaskManager(true);
		
		manager.addStartingTask(task1);
		manager.setFinalTask(task1);
		manager.addFinalPreconditions([finalPrecondition]);
				
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		
		var firstBlock = function () 
		{
			evaluator.registerRequiredTaskStatus({task:manager, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"completed"});
		
			manager.start();
		};
		
		var secondBlock = function ()
		{	
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
			
			manager.removeFinalPrecondition(finalPrecondition);
			
			evaluator.registerRequiredTaskStatus( {task: manager, event: "completed"} );
		};
		
		var thirdBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock,
			thirdBlock]
		);
		pauseAndResumer.start();
	}
	
	public function testRemoveFinalPreconditionBeforeStart () 
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var task1 : ITask = new FictiveTask();
		
		var finalPreconditionTask : ITask = new FictiveTask();
		var finalPrecondition : EventDescriptor = new EventDescriptor(
			finalPreconditionTask,			
			"completed"
		);
		
		var manager : TaskManager = new TaskManager(true);
		
		manager.addStartingTask(task1);
		manager.setFinalTask(task1);
		manager.addFinalPreconditions([finalPrecondition]);
				
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted, null));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted, null));
		
		var firstBlock = function () 
		{
			evaluator.registerRequiredTaskStatus({task:manager, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"completed"});
			evaluator.registerRequiredTaskStatus({task:manager, event:"completed"});
			
			manager.removeFinalPrecondition(finalPrecondition);
			manager.start();
		};
		
		var secondBlock = function ()
		{	
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock]
		);
		pauseAndResumer.start();
	}

	public function testRemoveTask ()
	{
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		var manager : TaskManager = new TaskManager();
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var task3 : ITask = new FictiveTask();
		
		manager.addStartingTask(task1);
		manager.addTaskWithPredecessor(task2, task1);
		manager.addTaskWithPredecessor(task3, task2);
		manager.setFinalTask(task3);
		manager.removeTask(task2);
		
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task2.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task2.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task3.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task3.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		var firstBlock = function ()
		{
			evaluator.registerRequiredTaskStatus({task: manager, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task1, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task1, event: "completed"});
			evaluator.registerRequiredTaskStatus({task: task3, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task3, event: "completed"});
			evaluator.registerRequiredTaskStatus({task: manager, event: "completed"});
			
			manager.start();
		};
		
		var secondBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock]
		);
		pauseAndResumer.start();
	}

	public function testRemovePredecessorTaskWhileRunning ()
	{
		// setup inventory
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var manager : TaskManager = new TaskManager();
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var task3 : ITask = new FictiveTask();
		var task4 : ITask = new FictiveTask();
		
		var preconditionTask : ITask = new FictiveTask();
		var precondition : EventDescriptor = new EventDescriptor(
			preconditionTask,
			"completed"
		);
		
		// setup manager
		manager.addStartingTask(task1);
		manager.addTaskWithPredecessor(task2, task1);
		manager.addTaskPrecondition(task2, precondition);
		manager.addTaskWithPredecessor(task3, task2);
		manager.addTaskWithPredecessor(task4, task3);
		manager.setFinalTask(task4);
		
		// attach evaluator listeners to the monitored tasks
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task2.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task2.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task3.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task3.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task4.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task4.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		// group the assertion code into distributed over time blocks
		var firstBlock = function ()
		{
			evaluator.registerRequiredTaskStatus({task: manager, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task1, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task1, event: "completed"});
			
			manager.start();
		};
		
		var secondBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
			
			evaluator.registerRequiredTaskStatus({task: task2, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task2, event: "completed"});
			evaluator.registerRequiredTaskStatus({task: task4, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task4, event: "completed"});
			evaluator.registerRequiredTaskStatus({task: manager, event: "completed"});
			
			manager.removeTask(task3);
			
			preconditionTask.start();
		};
		
		var thirdBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock,
			thirdBlock]
		);
		pauseAndResumer.start();
	}

	public function testReplaceTask ()
	{
		// setup inventory
		var evaluator : TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var manager : TaskManager = new TaskManager();
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		var task3 : ITask = new FictiveTask();
		var task4 : ITask = new FictiveTask();
		
		var preconditionTask : ITask = new FictiveTask();
		var precondition : EventDescriptor = new EventDescriptor(
			preconditionTask,
			"completed"
		);
		
		// setup manager
		manager.addStartingTask(task1);
		manager.addTaskWithPredecessor(task2, task1);
		manager.addTaskPrecondition(task2, precondition);
		manager.addTaskWithPredecessor(task3, task2);
		manager.setFinalTask(task3);
		
		// attach evaluator listeners to the monitored tasks
		manager.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		manager.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task1.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task1.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task2.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task2.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task3.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task3.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		task4.addEventListener("start", Delegate.create(evaluator, evaluator.onTaskStarted));
		task4.addEventListener("completed", Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		// group the assertion code into distributed over time blocks
		var firstBlock = function ()
		{
			evaluator.registerRequiredTaskStatus({task: manager, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task1, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task1, event: "completed"});
			
			manager.start();
		};
		
		var secondBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
			
			evaluator.registerRequiredTaskStatus({task: task2, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task2, event: "completed"});
			evaluator.registerRequiredTaskStatus({task: task4, event: "start"});
			evaluator.registerRequiredTaskStatus({task: task4, event: "completed"});
			evaluator.registerRequiredTaskStatus({task: manager, event: "completed"});
			
			manager.replaceTask(task3, task4);
			
			preconditionTask.start();
		};
		
		var thirdBlock = function ()
		{
			evaluator.evaluateTaskExecution();
			evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("registered task statuses doesnt match the required ones");
		};
		
		var pauseAndResumer : PauseResumeMethodsSequence = new PauseResumeMethodsSequence(
			this, 
			1000,
			[firstBlock,
			secondBlock,
			thirdBlock]
		);
		pauseAndResumer.start();
	}
	
	public function testMarkTask ()
	{
		var manager : TaskManager = new TaskManager();
		var task1 : ITask = new FictiveTask();
		var task2 : ITask = new FictiveTask();
		
		manager.addStartingTask(task1);
		manager.addTaskWithPredecessor(task2, task1);
		manager.setFinalTask(task2);
		
		manager.markTask(task2, "final");
		
		assertEquals(
			"getMarkedTask(marker) should match the marked task ",
			manager.getMarkedTask("final"),
			task2
		);
		
		assertEquals(
			"getTaskMarker(task) should match the marker",
			manager.getTaskMarker(task2),
			"final"		
		);
	}
	
	/**
	 * This test should assure that if we start the <code>TaskManager</code> 
	 * without final preconditions or final tasks specified, it will complete, 
	 * no matter whether the encapsulated tasks are completed.
	 */
	public function testCompletionWhenNoFinalPreconditionsSpecified() 
	{
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var taskManager:TaskManager = new TaskManager(true);
		taskManager.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		taskManager.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		var task1 : ITask = new XMLLoader();
		task1.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		task1.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		var task2 : ITask = new XMLLoader();
		task1.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		task1.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		var startTaskManager:Function = function()
		{
			taskManager.addStartingTask(task1);
			taskManager.addTaskWithPredecessor(task2, task1);
			
			taskManager.start();
			
			evaluator.registerRequiredTaskStatus({task:taskManager, event:"start"});
			evaluator.registerRequiredTaskStatus({task:task1, event:"start"});
			evaluator.registerRequiredTaskStatus({task:taskManager, event:"completed"});
		};
		
		var assertRegisteredEventsWereCaught:Function = function()
		{
			evaluator.evaluateTaskExecution();
		};
		
		var testSequence:PauseResumeMethodsSequence 
			= new PauseResumeMethodsSequence(
					this, 
					this.delayInterval, 
					[startTaskManager, 
					assertRegisteredEventsWereCaught]);
		
		testSequence.start();
	}
	
	private function emptyMethod()
	{
		// THIS METHOD SHOULD BE EMPTY!!!
	}
}